<?php defined('SYSPATH') or die('No direct script access.');
/**
 * 易宝支付
 *
 * @author  Yellow.Chow <aultoale@gmail.com>
 * @version $Id: alipay.php 82 2012-03-19 02:35:48Z yellow.chow $
 * @license http://www.gnu.org/licenses/gpl-3.0.html    GPL 3
 */
class Payment_Adapter_Yeepay extends Payment_Adapter
{

    /**
     * 支付方式参数
     *
     * @var array
     */
    protected $_config = array(
        'p0_Cmd'          => 'Buy', // 业务类型
        'p1_MerId'        => '', // 商户编号
        'p2_Order'        => '', // 商户订单号
        'p3_Amt'          => 0.0, // 支付金额
        'p4_Cur'          => 'CNY', // 交易币种
        'p5_Pid'          => '', // 商品名称
        'p6_Pcat'         => '', // 商品种类
        'p7_Pdesc'        => '', // 商品描述
        'p8_Url'          => '', // 商户接收支付响应数据的网址
        'p9_SAF'          => 0, // 是否需要用户将送货地址留在易宝支付系统
        'pa_MP'           => '', // 商户扩展信息，返回时原样返回
        'pd_FrpId'        => '', // 支付通道编码
        'pr_NeedResponse' => 1, // 是否需要应答机制
        'merchantKey'     => '', // 商户密钥
    );

    /**
     * 付款提交方法
     *
     * @var string
     */
    protected $_method = 'POST';

    /**
     * 设置订单编号
     *
     * @param  string  $id
     * @return Payment_Adapter_Yeepay
     */
    public function set_id($id)
    {
        $this->_config['p2_Order'] = $id;

        return $this;
    }

    /**
     * 设置订单主题
     *
     * @param  string  $subject
     * @return Payment_Adapter_Yeepay
     */
    public function set_subject($subject)
    {
        $this->_config['p5_Pid'] = $subject;

        return $this;
    }

    /**
     * 设置订单总金额
     *
     * @param  float  $amount
     * @return Payment_Adapter_Yeepay
     */
    public function set_amount($amount)
    {
        $this->_config['p3_Amt'] = $amount;

        return $this;
    }

    /**
     * 设置安全校验码
     *
     * @param  string  $key
     * @return Payment_Adapter_Yeepay
     */
    public function set_key($key)
    {
        $this->_config['merchantKey'] = $key;

        return $this;
    }

    /**
     * 设置支付通道编码
     *
     * @param  string  $frpid
     * @return Payment_Adapter_Yeepay
     */
    public function set_frpid($frpid)
    {
        $this->_config['pd_FrpId'] = $frpid;

        return $this;
    }

    /**
     * 获取支付网关地址
     *
     * @return string
     */
    public function get_gateway()
    {
        return 'https://www.yeepay.com/app-merchant-proxy/node'; // 正式接口
        // return 'http://tech.yeepay.com:8080/robot/debug.action'; // 测试接口
    }

    /**
     * 生成 HMAC 编码
     *
     * @param  string   $data
     * @param  string  $key
     */
    protected function _hmac($data, $key)
    {
        // RFC 2104 HMAC implementation for php.
        // Creates an md5 HMAC.
        // Eliminates the need to install mhash to compute a HMAC
        // Hacked by Lance Rushing(NOTE: Hacked means written)

        $b = 64; // byte length for md5
        if (strlen($key) > $b)
        {
            $key = pack("H*", md5($key));
        }
        $key = str_pad($key, $b, chr(0x00));
        $ipad = str_pad('', $b, chr(0x36));
        $opad = str_pad('', $b, chr(0x5c));
        $k_ipad = $key ^ $ipad ;
        $k_opad = $key ^ $opad;

        return md5($k_opad . pack("H*",md5($k_ipad . $data)));
    }

    /**
     * 获取数字签名
     *
     * @return string
     */
    public function get_sign()
    {
        extract($this->_config);

        // 进行签名处理，一定按照文档中标明的签名顺序进行
        $data = $p0_Cmd.$p1_MerId.$p2_Order.$p3_Amt.$p4_Cur.$p5_Pid.$p6_Pcat.
                $p7_Pdesc.$p8_Url.$p9_SAF.$pa_MP.$pd_FrpId.$pr_NeedResponse;

        return $this->_hmac($data, $merchantKey);
    }

    /**
     * 获取表单提交参数
     *
     * @return array
     */
    public function get_params()
    {
        $params = $this->_config;
        unset($params['merchantKey']);

        $params['hmac'] = $this->get_sign();

        return $params;
    }

    /**
     * 获取支付 URL
     *
     * @return string
     */
    public function get_payurl()
    {
        return $this->get_gateway().'?'.http_build_query($this->get_params());
    }

    /**
     * 对参数进行校验
     *
     * @return bool
     */
    public function is_valid()
    {
        try
        {
            $config = $this->_config;

            // 商户编号
            if ( ! preg_match('/^\d{10,12}$/', $config['p1_MerId']))
            {
                throw new Payment_Exception('p1_MerId：无效的商户编号');
            }

            // 商户订单号
            if ( ! preg_match('/^[a-z0-9\-]{8,50}$/i', $config['p2_Order']))
            {
                throw new Payment_Exception('p2_Order：无效的商户订单号');
            }

            // 订单总金额
            if (floatval($config['p3_Amt']) <= 0)
            {
                throw new Payment_Exception('p3_Amt：无效的订单总金额');
            }

            // 商品名称
            $config['p5_Pid'] = Str::slice(trim(strip_tags($config['p5_Pid'])), 20);
            if (empty($config['p5_Pid']))
            {
                throw new Payment_Exception('p5_Pid：商品名称不能为空');
            }

            // 商品种类
            $config['p6_Pcat'] = Str::slice($config['p6_Pcat'], 20);

            // 商品描述
            $config['p7_Pdesc'] = Str::slice($config['p7_Pdesc'], 20);

            // 支付响应 URL
            if ( ! empty($config['p8_Url']) AND ! Valid::url($config['p8_Url']))
            {
                throw new Payment_Exception('p8_Url：无效的支付响应 URL');
            }

            $this->_config = $config;

            return TRUE;
        }
        catch (Payment_Exception $e)
        {
            $this->_message = $e->getMessage();
            return FALSE;
        }
    }

    /**
     * 获取支付名称
     *
     * @return string
     */
    public function get_name()
    {
        return '易宝支付';
    }

}